#include <gtest/gtest.h>
#include <gmock/gmock.h>

#define private public
#define protected public
#include <section.h>
#undef private
#undef protected

using namespace std;
using ::testing::ContainerEq;


class AngleSteelTest: public::testing::Test
{
    protected:
        // Declares the AngleSteels
        double w1_ = 10.0, w2_ = 10.0, t1_ = 2.0, t2_ = 2.0;
        AngleSteel sect1_ = AngleSteel(1, w1_, w2_, t1_, t2_);

        // AngleSteel sect2_ = AngleSteel(2, 1.0, 0.0);

        // other data
        double area = w1_ * t1_ + w2_ * t2_ - t1_ * t2_;
        double Sy = w1_ * w2_ * w2_ / 2.0 +
                    (-(w1_ - t1_) * (w2_ - t2_) * (t1_ + (w2_ - t1_) / 2.0));
        double Sz  = (w1_ * w2_) * (w1_ / 2.0) +
                     (-(w1_ - t1_) * (w2_ - t2_) * (t2_ + (w1_ - t2_) / 2.0));
        double CGy = Sz / area;
        double CGz = Sy / area;

        double Iyy = (w1_ - t2_) * pow(t1_, 3.0) / 12.0 +
                     (w1_ - t2_) * t1_ * pow((CGz - t1_ / 2.0), 2.0) +
                     t2_ * pow(w2_, 3.0) / 12.0 +
                     (t2_ * w2_) * pow((CGz - w2_ / 2.0), 2.0);
        double Izz = w2_ * pow(t2_, 3.0) / 12.0 +
                     (w2_ * t2_) * pow((CGy - t2_ / 2.0), 2.0) +
                     t1_ * pow(w1_ - t2_, 3.0) / 12.0 +
                     (w1_ - t2_) * t1_ * pow(CGy - (w1_ - t2_) / 2.0 - t2_, 2.0);
        double yc1 = w1_ / 2.0;
        double zc1 = t1_ / 2.0;
        double A1 = w1_ * t1_;

        double yc2 = t2_ / 2.0;
        double zc2 = (w2_ - t1_) / 2.0 + t1_;
        double A2 = (w2_ - t1_) * t2_;

        double a1 = yc1 - CGy;
        double b1 = zc1 - CGz;
        double a2 = yc2 - CGy;
        double b2 = zc2 - CGz;
        double Iyz1 = a1 * b1 * A1;
        double Iyz2 = a2 * b2 * A2;
        double Iyz = Iyz1 + Iyz2;
        // You can remove any or all of the following functions if their bodies
        // would be empty.
        AngleSteelTest()
        {
            // You can do set-up work for each test here.
        };

        ~AngleSteelTest()
        {
            // You can do clean-up work that doesn't throw exceptions here.
        };

        // If the constructor and destructor are not enough for setting up
        // and cleaning up each test, you can define the following methods:
        void SetUp() override
        {
            // Code here will be called immediately after the constructor
            // (right before each test).
            cout << "Set Up AngleSteel Test" << endl;
        };

        void TearDown() override
        {
            // Code here will be called immediately after each test (right
            // before the destructor).
        };

        // Class members declared here can be used by all tests in the test
        // suite for Foo.
};


// Tests that the AngleSteel::AngleSteel() method does Abc.
TEST_F(AngleSteelTest, IsEmptyInitiate)
{
    cout << "\n---------- AngleSteelTest IsEmptyInitiate ----------" << endl;
    cout << "check id... " << endl;
    EXPECT_EQ(sect1_.id(), 1);
    // EXPECT_EQ(sect2_.id(), 2);

    cout << "check type... " << endl;
    char type[] = "AngleSteel";
    EXPECT_STREQ(type, sect1_.type_.c_str());

    cout << "check A... " << endl;
    EXPECT_DOUBLE_EQ(area, sect1_.A_);
    // EXPECT_DOUBLE_EQ(0.0, sect2_.A_);

    cout << "check Sy... " << endl;
    EXPECT_DOUBLE_EQ(Sy, sect1_.Sy_);

    cout << "check Sz... " << endl;
    EXPECT_DOUBLE_EQ(Sz, sect1_.Sz_);

    cout << "check CGy... " << endl;
    EXPECT_DOUBLE_EQ(CGy, sect1_.CGy_);

    cout << "check CGz... " << endl;
    EXPECT_DOUBLE_EQ(CGz, sect1_.CGz_);

    cout << "check SHy... " << endl;
    EXPECT_DOUBLE_EQ(0.0, sect1_.SHy_);

    cout << "check SHz... " << endl;
    EXPECT_DOUBLE_EQ(0.0, sect1_.SHz_);

    cout << "check Iyy_... " << endl;
    EXPECT_DOUBLE_EQ(Iyy, sect1_.Iyy_);

    cout << "check Izz_... " << endl;
    EXPECT_DOUBLE_EQ(Izz, sect1_.Izz_);

    cout << "check Iyz_... " << endl;
    EXPECT_DOUBLE_EQ(Iyz, sect1_.Iyz_);
};


// Tests that the AngleSteel::calcArea() method.
TEST_F(AngleSteelTest, A)
{
    cout << "\n---------- AngleSteelTest A ----------" << endl;
    cout << "check A..." << endl;
    EXPECT_DOUBLE_EQ(area, sect1_.A());
};


// Tests that the AngleSteel::Sy() method.
TEST_F(AngleSteelTest, Sy)
{
    cout << "\n---------- AngleSteelTest calcSy ----------" << endl;
    cout << "do nothing..." << endl;
    EXPECT_DOUBLE_EQ(Sy, sect1_.Sy());
};


// Tests that the AngleSteel::Sz() method does Abc.
TEST_F(AngleSteelTest, Sz)
{
    cout << "\n---------- AngleSteelTest Sz ----------" << endl;
    cout << "do nothing..." << endl;
    EXPECT_DOUBLE_EQ(Sz, sect1_.Sz());
};


// Tests that the AngleSteel::calcCGz() method does Abc.
TEST_F(AngleSteelTest, CGz)
{
    cout << "\n---------- AngleSteelTest CGz ----------" << endl;
    cout << "do nothing..." << endl;
    EXPECT_DOUBLE_EQ(CGz, sect1_.CGz());
};


// Tests that the AngleSteel::SHy() method does Abc.
TEST_F(AngleSteelTest, SHy)
{
    cout << "\n---------- AngleSteelTest SHy ----------" << endl;
    cout << "do nothing..." << endl;
    EXPECT_DOUBLE_EQ(0.0, sect1_.SHy());
};


// Tests that the AngleSteel::SHz() method does Abc.
TEST_F(AngleSteelTest, SHz)
{
    cout << "\n---------- AngleSteelTest SHz ----------" << endl;
    cout << "do nothing..." << endl;
    EXPECT_DOUBLE_EQ(0.0, sect1_.SHz());
};


// Tests that the AngleSteel::Iyy() method does Abc.
TEST_F(AngleSteelTest, Iyy)
{
    cout << "\n---------- AngleSteelTest Iyy ----------" << endl;
    cout << "do nothing..." << endl;
    EXPECT_DOUBLE_EQ(Iyy, sect1_.Iyy());
};


// Tests that the AngleSteel::calcIzz() method does Abc.
TEST_F(AngleSteelTest, Izz)
{
    cout << "\n---------- AngleSteelTest calcIzz ----------" << endl;
    cout << "do nothing..." << endl;
    EXPECT_DOUBLE_EQ(Izz, sect1_.Izz());
};


// Tests that the AngleSteel::calcIyz() method does Abc.
TEST_F(AngleSteelTest, Iyz)
{
    cout << "\n---------- AngleSteelTest calcIyz ----------" << endl;
    cout << "do nothing..." << endl;
    EXPECT_DOUBLE_EQ(Iyz, sect1_.Iyz());
};


// Tests that the AngleSteel::info() method does Abc.
TEST_F(AngleSteelTest, info)
{
    // do not need to test
};
